<?php

require_once 'Base64Url.php';

require_once 'AESEncrypter.php';

abstract class YopSignUtils
{
    /**
     * 签名生成算法.
     *
     * @param array  $params           API调用的请求参数集合的关联数组，不包含sign参数
     * @param array  $ignoreParamNames 忽略的参数数组
     * @param string $secret           密钥
     * @param string $algName          加密算法
     *
     * md2
     * md4
     * md5
     * sha1
     * sha256
     * sha384
     * sha512
     * ripemd128
     * ripemd160
     * ripemd256
     * ripemd320
     * whirlpool
     * @param mixed $debug
     *
     * @return string 返回参数签名值
     */
    public static function sign($params, $ignoreParamNames = '', $secret, $algName = 'sha256', $debug = false)
    {
        $str = '';  // 待签名字符串
        // 先将参数以其参数名的字典序升序进行排序
        $requestparams = $params;

        ksort($requestparams);
        // 遍历排序后的参数数组中的每一个key/value对
        foreach ($requestparams as $k => $v) {
            // 查看Key 是否为忽略参数
            if (!in_array($k, $ignoreParamNames)) {
                // 为key/value对生成一个keyvalue格式的字符串，并拼接到待签名字符串后面

                // value不为空,则进行加密
                if (!(null === $v)) {
                    $str .= "{$k}{$v}";
                }
            }
        }

        // 将签名密钥拼接到签名字符串两头
        $str = $secret . $str . $secret;
        // 通过指定算法生成sing

        $signValue = hash($algName, $str);

        if ($debug) {
            print_r($YopConfig);
            var_dump('algName=' . $algName);
            var_dump('str=' . $str);
            var_dump('signValue=' . $signValue);
        }

        return $signValue;
    }

    /**
     * 签名验证算法.
     *
     * @param array  $result  API调用的请求参数集合的关联数组，不包含sign参数
     * @param string $secret  密钥
     * @param string $algName 加密算法
     * @param string $sign    签名值
     *
     * @return string 返回签名是否正确 0 - 如果两个字符串相等
     */
    public static function isValidResult($result, $secret, $algName, $sign)
    {
//       var_dump($result);
//        $string=json_encode($result,true);
//        $string=json_decode($string,true);
//        var_dump($string);
        $Str = '';
        foreach ($result as $k => $v) {
            $Str .= 0 == strlen($Str) ? '' : '&';
            $Str .= $k . '=' . $v;
        }
        $newString = $secret . $Str . $secret;
//       echo $newString;
        if (0 == strcasecmp($sign, hash($algName, $newString))) {
            return true;
        }

        return false;
    }

    public static function decrypt($source, $private_Key, $public_Key)
    {
        $private_key = "-----BEGIN RSA PRIVATE KEY-----\n" .
           wordwrap($private_Key, 64, "\n", true) .
           "\n-----END RSA PRIVATE KEY-----";

        extension_loaded('openssl') or exit('php需要openssl扩展支持');

        /* 提取私钥 */
        $privateKey = openssl_get_privatekey($private_key);

        ($privateKey) or exit('密钥不可用');

        // 分解参数
        $args = explode('$', $source);

        if (4 != count($args)) {
            exit('source invalid : ');
        }

        $encryptedRandomKeyToBase64 = $args[0];
        $encryptedDataToBase64 = $args[1];
        $symmetricEncryptAlg = $args[2];
        $digestAlg = $args[3];

        // 用私钥对随机密钥进行解密
        openssl_private_decrypt(Base64Url::decode($encryptedRandomKeyToBase64), $randomKey, $privateKey);
        openssl_free_key($privateKey);
        $encryptedData = openssl_decrypt(Base64Url::decode($encryptedDataToBase64), 'AES-128-ECB', $randomKey, OPENSSL_RAW_DATA);
        // 分解参数
        $signToBase64 = substr(strrchr($encryptedData, '$'), 1);
        $sourceData = substr($encryptedData, 0, strlen($encryptedData) - strlen($signToBase64) - 1);

        $public_key = "-----BEGIN PUBLIC KEY-----\n" .
           wordwrap($public_Key, 64, "\n", true) .
           "\n-----END PUBLIC KEY-----";

        $publicKey = openssl_pkey_get_public($public_key);

        $res = openssl_verify($sourceData, Base64Url::decode($signToBase64), $publicKey, $digestAlg); // 验证

        openssl_free_key($publicKey);

        // 输出验证结果，1：验证成功，0：验证失败
        if (1 == $res) {
            return $sourceData;
        }

        exit('verifySign fail!');
    }

    public static function signRsa($source, $private_Key)
    {
        $private_key = "-----BEGIN RSA PRIVATE KEY-----\n" .
            wordwrap($private_Key, 64, "\n", true) .
            "\n-----END RSA PRIVATE KEY-----";

        extension_loaded('openssl') or exit('php需要openssl扩展支持');

        /* 提取私钥 */
        $privateKey = openssl_get_privatekey($private_key);

        ($privateKey) or exit('密钥不可用');

        openssl_sign($source, $encode_data, $privateKey, 'SHA256');

        openssl_free_key($privateKey);

        $signToBase64 = Base64Url::encode($encode_data);

        $signToBase64 .= '$SHA256';

        return $signToBase64;
    }

    public static function getPrivateKey($filepath, $password)
    {
        // var_dump($filepath);
        $pkcs12 = file_get_contents($filepath);
        openssl_pkcs12_read($pkcs12, $certs, $password);
        $prikeyid = $certs['pkey']; // 私钥

        $prikeyid = str_replace('-----BEGIN RSA PRIVATE KEY-----', '', $prikeyid);
        $prikeyid = str_replace('-----END RSA PRIVATE KEY-----', '', $prikeyid);

        return preg_replace("/(\r\n|\n|\r|\t)/i", '', $prikeyid);
    }

    public static function verifySign($source, $sign, $public_Key)
    {
        $content = strstr($source, '&sign', true);
        $public_key = "-----BEGIN PUBLIC KEY-----\n" .
            wordwrap($public_Key, 64, "\n", true) .
            "\n-----END PUBLIC KEY-----";

        $publicKey = openssl_pkey_get_public($public_key);
        $res = openssl_verify($content, Base64Url::decode($sign), $public_key, 'SHA256'); // 验证

        openssl_free_key($publicKey);
        // 输出验证结果，1：验证成功，0：验证失败
        if (1 == $res) {
            return true;
        }

        exit('verifySign fail!');
    }
}
